home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / MSDOS.C < prev    next >
C/C++ Source or Header  |  1993-03-05  |  27KB  |  1,094 lines

  1. /*    MSDOS.C:    Operating specific I/O and Spawning functions
  2.             under the MS/PCDOS operating system
  3.             for MicroEMACS 3.12
  4.             (C)Copyright 1993 by Daniel M. Lawrence
  5. */
  6.  
  7. #include        <stdio.h>
  8. #include    "estruct.h"
  9. #include    "eproto.h"
  10.  
  11. #ifdef    MSDOS
  12. #include        "edef.h"
  13. #include    "elang.h"
  14.  
  15. /* The Mouse driver only works with typeahead defined */
  16. #if    MOUSE
  17. #undef    TYPEAH
  18. #define    TYPEAH    1
  19. #endif
  20.  
  21. #if  TURBO
  22. #include <conio.h>
  23. #include <dir.h>
  24. #include <dos.h>
  25. #include <bios.h>
  26.  
  27. struct ffblk fileblock;    /* structure for directory searches */
  28. #endif
  29. #if    MSC | ZTC
  30. #include <dos.h>
  31.  
  32. struct find_t fileblock;    /* structure for directory searches */
  33. #endif
  34.  
  35. #if     LATTICE | MSC | DTL | TURBO | IC | AZTEC | MWC | ZTC
  36. union REGS rg;        /* cpu register for use of DOS calls */
  37. struct SREGS segreg;    /* cpu segment registers         */
  38. int nxtchar = -1;    /* character held from type ahead    */
  39. #endif
  40.  
  41. #if    MSC | TURBO
  42. #include    <process.h>
  43. #endif
  44.  
  45. #if    IC
  46. #include    <time.h>
  47. #endif
  48.  
  49. /*    Some global variable    */
  50. #define INBUFSIZ    40
  51. static int mexist;    /* is the mouse driver installed? */
  52. static int nbuttons;    /* number of buttons on the mouse */
  53. static int oldbut;    /* Previous state of mouse buttons */
  54. static int oldcol;    /* previous x position of mouse */
  55. static int oldrow;    /* previous y position of mouse */
  56.  
  57. int PASCAL NEAR execprog(char *cmd);
  58.  
  59. /*    input buffers and pointers    */
  60.  
  61. #define    IBUFSIZE    64    /* this must be a power of 2 */
  62.  
  63. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  64. int in_next = 0;        /* pos to retrieve next input character */
  65. int in_last = 0;        /* pos to place most recent input character */
  66.  
  67. in_init()    /* initialize the input buffer */
  68.  
  69. {
  70.     in_next = in_last = 0;
  71. }
  72.  
  73. in_check()    /* is the input buffer non-empty? */
  74.  
  75. {
  76.     if (in_next == in_last)
  77.         return(FALSE);
  78.     else
  79.         return(TRUE);
  80. }
  81.  
  82. in_put(event)
  83.  
  84. int event;    /* event to enter into the input buffer */
  85.  
  86. {
  87.     in_buf[in_last++] = event;
  88.     in_last &= (IBUFSIZE - 1);
  89. }
  90.  
  91. int in_get()    /* get an event from the input buffer */
  92.  
  93. {
  94.     register int event;    /* event to return */
  95.  
  96.     event = in_buf[in_next++];
  97.     in_next &= (IBUFSIZE - 1);
  98.     return(event);
  99. }
  100.  
  101. /*
  102.  * This function is called once to set up the terminal device streams.
  103.  */
  104.  
  105. int PASCAL NEAR ttopen()
  106.  
  107. {
  108. #if    MOUSE
  109.     long miaddr;    /* mouse interupt routine address */
  110. #endif
  111.  
  112.     /* on all screens we are not sure of the initial position
  113.        of the cursor                    */
  114.     ttrow = 999;
  115.     ttcol = 999;
  116.     strcpy(os, "MSDOS");
  117.  
  118. #if    MOUSE
  119.     /* check if the mouse drive exists first */
  120.     rg.x.ax = 0x3533;    /* look at the interrupt 33 address */
  121. #if    MSC | TURBO | IC | DTL | LATTICE | MWC
  122.     int86x(0x21, &rg, &rg, &segreg);
  123.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  124.     if (miaddr == 0 || *(char * far)miaddr == 0xcf) {
  125. #endif
  126. #if    ZTC
  127.     int86x(0x21, &rg, &rg, &segreg);
  128.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  129.     if (miaddr == 0 || *(char far *)miaddr == 0xcf) {
  130. #endif
  131. #if    AZTEC
  132.     sysint(0x21, &rg, &rg);
  133.     miaddr = (((long)rg.x.es) << 16) + (long)rg.x.bx;
  134.     if (miaddr == 0 || *(char *)miaddr == 0xcf) {
  135. #endif
  136.         mexist = FALSE;
  137.         return(TRUE);
  138.     }
  139.  
  140.     /* and then check for the mouse itself */
  141.     rg.x.ax = 0;        /* mouse status flag */
  142.     int86(0x33, &rg, &rg);    /* check for the mouse interupt */
  143.     mexist = (rg.x.ax != 0);
  144.     nbuttons = rg.x.bx;
  145.  
  146.     /* initialize our character input queue */
  147.     in_init();
  148.     if (mexist == FALSE)
  149.         return(TRUE);
  150.  
  151.     /* if the mouse exists.. get it in the upper right corner */
  152.     rg.x.ax = 4;        /* set mouse cursor position */
  153.     oldcol = (term.t_ncol - 1);
  154.     rg.x.cx = oldcol << 3;    /* last col of display */
  155.     oldrow = 0;
  156.     rg.x.dx = oldrow;    /* top row */
  157.     oldbut = 0;
  158.     int86(0x33, &rg, &rg);
  159.  
  160.     /* and set its attributes */
  161.     rg.x.ax = 10;        /* set text cursor */
  162.     rg.x.bx = 0;        /* software text cursor please */
  163.     rg.x.cx = 0x77ff;    /* screen mask */
  164.     rg.x.dx = 0x7700;    /* cursor mask */
  165.     int86(0x33, &rg, &rg);
  166. #else    /* !MOUSE */
  167.     mexist = 0;
  168. #endif    /* !MOUSE */
  169. }
  170.  
  171. maxlines(lines)        /* set number of vertical rows for mouse */
  172.  
  173. int lines;    /* # of vertical lines */
  174.  
  175. {
  176. #if    MOUSE
  177.     if (mexist) {
  178.         rg.x.ax = 8;        /* set min/max vertical cursor position */
  179.         rg.x.cx = 0;        /* start at 0 */
  180.         rg.x.dx = (lines - 1)<<3; /* end at the end */
  181.         int86(0x33, &rg, &rg);
  182.     }
  183. #endif
  184. }
  185.  
  186. /*
  187.  * This function gets called just before we go back home to the command
  188.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  189.  * Another no-operation on CPM.
  190.  */
  191. int PASCAL NEAR ttclose()
  192. {
  193.     /* nothing here! */
  194. }
  195.  
  196. /*
  197.  * Write a character to the display. On VMS, terminal output is buffered, and
  198.  * we just put the characters in the big array, after checking for overflow.
  199.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  200.  * MS-DOS (use the very very raw console output routine).
  201.  */
  202.  
  203. int PASCAL NEAR ttputc(c)
  204.  
  205. int c;
  206.  
  207. {
  208. #if     MWC
  209.         putcnb(c);
  210. #endif
  211.  
  212. #if    (LATTICE | AZTEC | TURBO | IC | MSC | ZTC) & ~IBMPC
  213.     bdos(6, c, 0);
  214. #endif
  215. }
  216.  
  217. /*
  218.  * Flush terminal buffer. Does real work where the terminal output is buffered
  219.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  220.  */
  221. int PASCAL NEAR ttflush()
  222. {
  223. }
  224.  
  225. int doschar()    /* call the dos to get a char */
  226.  
  227. {
  228. #if ATKBD    /* AT-style extended keyboard with grey keys */
  229.  
  230.     rg.h.ah = 0x10;            /* Get Keyboard Input call */
  231.     int86(0x16, &rg, &rg);
  232.  
  233.     /* function key!! */
  234.     if (rg.h.al == 0 || rg.h.al == 0xE0) {
  235.  
  236.         rg.h.cl = rg.h.ah;    /* swap scan code and value */
  237.         rg.h.ch = rg.h.al;
  238.         rg.x.cx = extcode(rg.x.cx);
  239.         in_put(rg.h.ch & 255);    /* prefix byte */
  240.         in_put(rg.h.cl & 255);    /* event code byte */
  241.         return(0);        /* extended escape sequence */
  242.     }
  243.     return(rg.h.al & 255);
  244. #else
  245.  
  246. #if    (TURBO | IC) && HP150 == 0
  247. /*    Added 8/13/89 by DRK to get Turbo C version to use BIOS for
  248.     keyboard input. Low byte of k has first byte of extended scan
  249.     (ASCII value for reg. char, 0 for extended char), high byte has
  250.     extended key scan code.
  251. */
  252.  
  253.     unsigned k = (unsigned)bioskey(0);
  254.     unsigned c;        /* Extended character to return. */
  255.  
  256.     if ((k & 0xFF) == 0) {    /* Check for extended key. */
  257.                 /* Convert extended key scan code to a
  258.                    uEMACS internal form. */
  259.         c = extcode(k >> 8);
  260.         in_put(c >> 8);    /* Report prefix and event code bytes. */
  261.         in_put(c & 0xFF);
  262.         return(0);    /* Return extended escape sequence. */
  263.     }
  264.     return (k & 0xFF);    /* Return regular ASCII value. */
  265.  
  266. #else
  267.     register unsigned int c;    /* extended character to return */ 
  268.  
  269.     rg.h.ah = 7;        /* dos Direct Console Input call */
  270.     intdos(&rg, &rg);
  271. #if    HP150 == 0        /* this translation level is deeper on the HP150 */
  272.     if (rg.h.al == 0) {    /* function key!! */
  273.         rg.h.ah = 7;    /* get the next character */
  274.         intdos(&rg, &rg);
  275.         c = extcode(rg.h.al);
  276.         in_put(c >> 8);        /* prefix byte */
  277.         in_put(c & 255);    /* event code byte */
  278.         return(0);        /* extended escape sequence */
  279.     }
  280. #endif
  281.     return(rg.h.al & 255);
  282. #endif
  283. #endif
  284. }
  285.  
  286. /*
  287.  * Read a character from the terminal, performing no editing and doing no echo
  288.  * at all. Also mouse events are forced into the input stream here.
  289.  */
  290. int PASCAL NEAR ttgetc()
  291.  
  292. {
  293.     register int c;        /* character read */
  294.  
  295. ttc:    /* return any keystrokes waiting in the
  296.        type ahead buffer */
  297.     if (in_check())
  298.         return(in_get());
  299.  
  300. #if    TYPEAH
  301.     if (typahead())
  302.         return(doschar());
  303.  
  304.     /* with no mouse, this is a simple get char routine */
  305.     if (mexist == FALSE || mouseflag == FALSE)
  306.         return(doschar());
  307.  
  308. #if    MOUSE
  309.     /* turn the mouse cursor on */
  310.     rg.x.ax = 1;    /* Show Cursor */
  311.     int86(0x33, &rg, &rg);
  312.  
  313.     /* loop waiting for something to happen */
  314.     while (TRUE) {
  315.         if (typahead())
  316.             break;
  317.         if (checkmouse())
  318.             break;
  319.     }
  320.  
  321.     /* turn the mouse cursor back off */
  322.     rg.x.ax = 2;    /* Hide Cursor */
  323.     int86(0x33, &rg, &rg);
  324.  
  325.     goto ttc;
  326. #endif    /* MOUSE */
  327. #else    /* TYPEAH */
  328.     return(doschar());
  329. #endif    /* TYPEAH */
  330. }
  331.  
  332. #if    MOUSE
  333. checkmouse()
  334.  
  335. {
  336.     register int k;        /* current bit/button of mouse */
  337.     register int etype;    /* event type byte */
  338.     register int event;    /* encoded mouse event */
  339.     int mousecol;        /* current mouse column */
  340.     int mouserow;        /* current mouse row */
  341.     int sstate;        /* current shift key status */
  342.     int newbut;        /* new state of the mouse buttons */
  343.  
  344.     /* check to see if any mouse buttons are different */
  345.     rg.x.ax = 3;    /* Get button status and mouse position */
  346.     int86(0x33, &rg, &rg);
  347.     newbut = rg.x.bx;
  348.     if (strcmp(sres, "CGA40") == 0)
  349.         mousecol = rg.x.cx >> 4;
  350.     else /* if (term.t_ncol == 80) */
  351.         mousecol = rg.x.cx >> 3;
  352.     mouserow = (rg.x.dx >> 3);
  353.  
  354.     /* only notice changes */
  355.     if ((oldbut == newbut) && (mousecol == oldcol)
  356.         && (mouserow == oldrow))
  357.         return(FALSE);
  358.  
  359.     /* get the shift key status as well */
  360.     etype = MOUS >> 8;
  361.     sstate = 0;
  362.     rg.h.ah = 2;    /* return current shift status */
  363.     int86(0x16, &rg, &rg);
  364.     sstate = rg.h.al;
  365.     if (sstate & 3)        /* shifted? */
  366.         etype |= (SHFT >> 8);
  367.     if (sstate & 4)        /* controled? */
  368.         etype |= (CTRL >> 8);
  369.  
  370.     /* no buttons changes */
  371.     if (oldbut == newbut) {
  372.  
  373.         /* generate a mouse movement */
  374.         if (((mouse_move == 1) && (mmove_flag == TRUE)) ||
  375.             (mouse_move == 2)) {
  376.             in_put(0);
  377.             in_put(etype);
  378.             in_put(mousecol);
  379.             in_put(mouserow);
  380.             in_put('m');
  381.         }
  382.         oldcol = mousecol;
  383.         oldrow = mouserow;
  384.         return(TRUE);
  385.     }
  386.  
  387.     /* only on screen presses are legit! */
  388.     if (mousecol < 0)
  389.         mousecol = 0;
  390.     if (mouserow < 0)
  391.         mouserow = 0;
  392.  
  393.     for (k=1; k != (1 << nbuttons); k = k<<1) {
  394.         /* For each button on the mouse */
  395.         if ((oldbut&k) != (newbut&k)) {
  396.             /* This button changed, generate an event */
  397.             in_put(0);
  398.             in_put(etype);
  399.             in_put(mousecol);
  400.             in_put(mouserow);
  401.  
  402.             event = ((newbut&k) ? 0 : 1);    /* up or down? */
  403.             if (k == 2)            /* center button? */
  404.                 event += 4;
  405.             if (k == 4)            /* right button? */
  406.                 event += 2;
  407.             event += 'a';        /* plain */
  408.             in_put(event);
  409.             oldbut = newbut;
  410.             oldcol = mousecol;
  411.             oldrow = mouserow;
  412.             return(TRUE);
  413.         }
  414.     }
  415.     return(FALSE);
  416. }
  417. #endif
  418.  
  419. #if    TYPEAH
  420. /* typahead:    Check to see if any characters are already in the
  421.         keyboard buffer
  422. */
  423.  
  424. int PASCAL NEAR typahead()
  425.  
  426. {
  427.     int flags;    /* cpu flags from dos call */
  428.  
  429. #if    (TURBO | IC ) && HP150 == 0 && ATKBD == 0
  430.     if (bioskey(1) == 0)
  431.         return FALSE;
  432.     else
  433.         return TRUE;
  434. #else
  435.     rg.x.ax = 0x4406;    /* IOCTL input status */
  436.     rg.x.bx = 0;        /* File handle = stdin */
  437. #if    MSC | DTL
  438.     int86(0x21,&rg,&rg);
  439.     flags = rg.h.al;
  440. #else
  441. #if    LATTICE | AZTEC | TURBO | IC | ZTC
  442.     flags = intdos(&rg, &rg);
  443. #else
  444.     intcall(&rg, &rg, 0x21);
  445.     flags = rg.x.flags;
  446. #endif
  447. #endif
  448.     if (flags & 1)        /* AL = 0xFF if ready */
  449.         return(TRUE);
  450.     else
  451.         return(FALSE);
  452. #endif
  453. }
  454. #endif
  455.  
  456. /*
  457.  * Create a subjob with a copy of the command intrepreter in it. When the
  458.  * command interpreter exits, mark the screen as garbage so that you do a full
  459.  * repaint. Bound to "^X C".
  460.  */
  461.  
  462. int PASCAL NEAR spawncli(f, n)
  463.  
  464. int f, n;
  465.  
  466. {
  467.     /* don't allow this command if restricted */
  468.     if (restflag)
  469.         return(resterr());
  470.  
  471.         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  472.         TTflush();
  473.     TTkclose();
  474.     shellprog("");
  475. #if    WINDOW_TEXT
  476.     refresh_screen(first_screen);
  477. #endif
  478.     TTkopen();
  479.         sgarbf = TRUE;
  480.         return(TRUE);
  481. }
  482.  
  483. /*
  484.  * Run a one-liner in a subjob. When the command returns, wait for a single
  485.  * character to be typed, then mark the screen as garbage so a full repaint is
  486.  * done. Bound to "C-X !".
  487.  */
  488. int PASCAL NEAR spawn(f, n)
  489.  
  490. int f, n;
  491.  
  492. {
  493.         register int s;
  494.         char line[NLINE];
  495.  
  496.     /* don't allow this command if restricted */
  497.     if (restflag)
  498.         return(resterr());
  499.  
  500.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  501.                 return(s);
  502.     movecursor(term.t_nrow - 1, 0);
  503.     TTkclose();
  504.         shellprog(line);
  505.     TTkopen();
  506.  
  507.     /* if we are interactive, pause here */
  508.     if (clexec == FALSE) {
  509.         printf(TEXT227);
  510. /*            "\n--- Press any key to Continue ---" */
  511.         tgetc();
  512.         }
  513. #if    WINDOW_TEXT
  514.     refresh_screen(first_screen);
  515. #endif
  516.         sgarbf = TRUE;
  517.         return (TRUE);
  518. }
  519.  
  520. /*
  521.  * Run an external program with arguments. When it returns, wait for a single
  522.  * character to be typed, then mark the screen as garbage so a full repaint is
  523.  * done. Bound to "C-X $".
  524.  */
  525.  
  526. int PASCAL NEAR execprg(f, n)
  527.  
  528. {
  529.         register int s;
  530.         char line[NLINE];
  531.  
  532.     /* don't allow this command if restricted */
  533.     if (restflag)
  534.         return(resterr());
  535.  
  536.         if ((s=mlreply("$", line, NLINE)) != TRUE)
  537.                 return(s);
  538.     movecursor(term.t_nrow - 1, 0);
  539.     TTkclose();
  540.         execprog(line);
  541. #if    WINDOW_TEXT
  542.     refresh_screen(first_screen);
  543. #endif
  544.     TTkopen();
  545.     /* if we are interactive, pause here */
  546.     if (clexec == FALSE) {
  547.             mlputs(TEXT6);
  548. /*                     "\r\n\n[End]" */
  549.             tgetc();
  550.         }
  551.         sgarbf = TRUE;
  552.         return (TRUE);
  553. }
  554.  
  555. /*
  556.  * Pipe a one line command into a window
  557.  * Bound to ^X @
  558.  */
  559. int PASCAL NEAR pipecmd(f, n)
  560.  
  561. int f, n;
  562.  
  563. {
  564.     register WINDOW *wp;    /* pointer to new window */
  565.     register BUFFER *bp;    /* pointer to buffer to zot */
  566.     register char *tmp;    /* ptr to TMP DOS environment variable */
  567.     FILE *fp;
  568.         char line[NLINE];    /* command line send to shell */
  569.     static char bname[] = "command";
  570.     static char filnam[NSTRING] = "command";
  571.     char *getenv();
  572.  
  573.     /* don't allow this command if restricted */
  574.     if (restflag)
  575.         return(resterr());
  576.  
  577.     if ((tmp = getenv("TMP")) == NULL)
  578.         filnam[0] = 0;
  579.     else {
  580.         strcpy(filnam, tmp);
  581.         if (filnam[strlen(filnam) - 1] != '\\')
  582.             strcat(filnam, "\\");
  583.         }
  584.     strcat(filnam,"command");
  585.  
  586.     /* get the command to pipe in */
  587.         if (mlreply("@", line, NLINE) != TRUE)
  588.                 return(FALSE);
  589.  
  590.     /* get rid of the command output buffer if it exists */
  591.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  592.         /* try to make sure we are off screen */
  593.         wp = wheadp;
  594.         while (wp != NULL) {
  595.             if (wp->w_bufp == bp) {
  596.                 onlywind(FALSE, 1);
  597.                 break;
  598.             }
  599.             wp = wp->w_wndp;
  600.         }
  601.         /* get rid of the existing command buffer */
  602.         if (zotbuf(bp) != TRUE)
  603.             return(FALSE);
  604.     }
  605.  
  606.     /* redirect the command output to the output file */
  607.     strcat(line, " >>");
  608.     strcat(line, filnam);
  609.     movecursor(term.t_nrow - 1, 0);
  610.  
  611.     /* execute the command */
  612.     TTkclose();
  613.         shellprog(line);
  614. #if    WINDOW_TEXT
  615.     refresh_screen(first_screen);
  616. #endif
  617.     TTkopen();
  618.         sgarbf = TRUE;
  619.  
  620.         /* did the output file get generated? */
  621.     if ((fp = fopen(filnam, "r")) == NULL)
  622.         return(FALSE);
  623.     fclose(fp);
  624.  
  625.     /* split the current window to make room for the command output */
  626.     if (splitwind(FALSE, 1) == FALSE)
  627.             return(FALSE);
  628.  
  629.     /* and read the stuff in */
  630.     if (getfile(filnam, FALSE) == FALSE)
  631.         return(FALSE);
  632.  
  633.     /* make this window in VIEW mode, update all mode lines */
  634.     curwp->w_bufp->b_mode |= MDVIEW;
  635.     wp = wheadp;
  636.     while (wp != NULL) {
  637.         wp->w_flag |= WFMODE;
  638.         wp = wp->w_wndp;
  639.     }
  640.  
  641.     /* and get rid of the temporary file */
  642.     unlink(filnam);
  643.     return(TRUE);
  644. }
  645.  
  646. /*
  647.  * filter a buffer through an external DOS program
  648.  * Bound to ^X #
  649.  */
  650. int PASCAL NEAR filter(f, n)
  651.  
  652. int f, n;
  653.  
  654. {
  655.         register int    s;    /* return status from CLI */
  656.     register BUFFER *bp;    /* pointer to buffer to zot */
  657.         char line[NLINE];    /* command line send to shell */
  658.     char tmpnam[NFILEN];    /* place to store real file name */
  659.     static char bname1[] = "fltinp";
  660.  
  661.     static char filnam1[] = "fltinp";
  662.     static char filnam2[] = "fltout";
  663.  
  664.     /* don't allow this command if restricted */
  665.     if (restflag)
  666.         return(resterr());
  667.  
  668.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  669.         return(rdonly());    /* we are in read only mode    */
  670.  
  671.     /* get the filter name and its args */
  672.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  673.                 return(s);
  674.  
  675.     /* setup the proper file names */
  676.     bp = curbp;
  677.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  678.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  679.  
  680.     /* write it out, checking for errors */
  681.     if (writeout(filnam1, "w") != TRUE) {
  682.         mlwrite(TEXT2);
  683. /*                      "[Cannot write filter file]" */
  684.         strcpy(bp->b_fname, tmpnam);
  685.         return(FALSE);
  686.     }
  687.  
  688.     strcat(line," <fltinp >fltout");
  689.     movecursor(term.t_nrow - 1, 0);
  690.     TTkclose();
  691.         shellprog(line);
  692. #if    WINDOW_TEXT
  693.     refresh_screen(first_screen);
  694. #endif
  695.     TTkopen();
  696.         sgarbf = TRUE;
  697.     s = TRUE;
  698.  
  699.     /* on failure, escape gracefully */
  700.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  701.         mlwrite(TEXT3);
  702. /*                      "[Execution failed]" */
  703.         strcpy(bp->b_fname, tmpnam);
  704.         unlink(filnam1);
  705.         unlink(filnam2);
  706.         return(s);
  707.     }
  708.  
  709.     /* reset file name */
  710.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  711.     bp->b_flag |= BFCHG;        /* flag it as changed */
  712.  
  713.     /* and get rid of the temporary file */
  714.     unlink(filnam1);
  715.     unlink(filnam2);
  716.     return(TRUE);
  717. }
  718.  
  719. #if    LATTICE
  720. extern int _oserr;
  721. #endif
  722.  
  723. #if    AZTEC | MWC
  724. extern int errno;
  725. #endif
  726.  
  727. #if    MSC
  728. extern int _doserrno;
  729. #endif
  730.  
  731. /*    SHELLPROG: Execute a command in a subshell        */
  732.  
  733. int PASCAL NEAR shellprog(cmd)
  734.  
  735. char *cmd;    /*  Incoming command line to execute  */
  736.  
  737. {
  738.     char *shell;        /* Name of system command processor */
  739.     char swchar;        /* switch character to use */
  740.     union REGS regs;    /* parameters for dos call */
  741.     char comline[NSTRING];    /* constructed command line */
  742.     char *getenv();
  743.  
  744.     /*  detect current switch character and set us up to use it */
  745.     regs.h.ah = 0x37;    /*  get setting data  */
  746.     regs.h.al = 0x00;    /*  get switch character  */
  747.     intdos(®s, ®s);
  748.     swchar = (char)regs.h.dl;
  749.  
  750.     /*  get name of system shell  */
  751.     if ((shell = getenv("COMSPEC")) == NULL) {
  752.         return(FALSE);        /*  No shell located  */
  753.     }
  754.  
  755.     /* trim leading whitespace off the command */
  756.     while (*cmd == ' ' || *cmd == '\t')    /*  find out if null command */
  757.         cmd++;
  758.  
  759.     /**  If the command line is not empty, bring up the shell  **/
  760.     /**  and execute the command.  Otherwise, bring up the     **/
  761.     /**  shell in interactive mode.   **/
  762.  
  763.     if (*cmd) {
  764.         strcpy(comline, shell);
  765.         strcat(comline, " ");
  766.         comline[strlen(comline) + 1] = 0;
  767.         comline[strlen(comline)] = swchar;
  768.         strcat(comline, "c ");
  769.         strcat(comline, cmd);
  770.         return(execprog(comline));
  771.     } else
  772.         return(execprog(shell));
  773. }
  774.  
  775. /*    EXECPROG:    A function to execute a named program
  776.             with arguments
  777. */
  778.  
  779. #if    LATTICE | AZTEC | MWC
  780. #define    CFLAG    1
  781. #endif
  782.  
  783. int PASCAL NEAR execprog(cmd)
  784.  
  785. char *cmd;    /*  Incoming command line to execute  */
  786.  
  787. {
  788.     char *sp;        /* temporary string pointer */
  789.     char f1[38];        /* FCB1 area (not initialized */
  790.     char f2[38];        /* FCB2 area (not initialized */
  791.     char prog[NSTRING];    /* program filespec */
  792.     char tail[NSTRING];    /* command tail with length byte */
  793.     union REGS regs;    /* parameters for dos call  */
  794. #if    MWC == 0
  795.     struct SREGS segreg;    /* segment registers for dis call */
  796. #endif
  797.     struct Pblock {        /* EXEC parameter block */
  798.         short envptr;    /* 2 byte pointer to environment string */
  799.         char *cline;    /* 4 byte pointer to command line */
  800.         char *fcb1;    /* 4 byte pointer to FCB at PSP+5Ch */
  801.         char *fcb2;    /* 4 byte pointer to FCB at PSP+6Ch */
  802.     } pblock;
  803.  
  804.     /* parse the command name from the command line */
  805.     sp = prog;
  806.     while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
  807.         *sp++ = *cmd++;
  808.     *sp = 0;
  809.  
  810.     /* and parse out the command tail */
  811.     while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
  812.         ++cmd;
  813.     *tail = (char)(strlen(cmd)); /* record the byte length */
  814.     strcpy(&tail[1], cmd);
  815.     strcat(&tail[1], "\r");
  816.  
  817.     /* look up the program on the path trying various extentions */
  818.     if ((sp = flook(prog, TRUE)) == NULL)
  819.         if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
  820.             strcpy(&prog[strlen(prog)-4], ".com");
  821.             if ((sp = flook(prog, TRUE)) == NULL)
  822.                 return(FALSE);
  823.         }
  824.     strcpy(prog, sp);
  825.  
  826. #if    MWC == 0
  827.     /* get a pointer to this PSPs environment segment number */
  828. #if    IC
  829.     _segread(&segreg);
  830. #else /* IC */
  831.     segread(&segreg);
  832. #endif /* IC */
  833. #endif /* MWC == 0 */
  834.  
  835.     /* set up the EXEC parameter block */
  836.     pblock.envptr = 0;    /* make the child inherit the parents env */
  837.     pblock.fcb1 = f1;        /* point to a blank FCB */
  838.     pblock.fcb2 = f2;        /* point to a blank FCB */
  839.         pblock.cline = tail;        /* parameter line pointer */
  840.  
  841.     /* and make the call */
  842.     regs.h.ah = 0x4b;    /* EXEC Load or Execute a Program */
  843.     regs.h.al = 0x00;    /* load end execute function subcode */
  844. #if    AZTEC | MWC
  845.     regs.x.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  846.     regs.x.dx = (unsigned int)(prog);
  847.     regs.x.es = regs.x.ds;
  848.     /*regs.x.es = ((unsigned long)(&pblock) >> 16);    * set up param block ptr */
  849.     regs.x.bx = (unsigned int)(&pblock);
  850. #endif
  851. #if    LATTICE | MSC | TURBO | IC | DTL | ZTC
  852.     segreg.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  853.     regs.x.dx = (unsigned int)(prog);
  854.     segreg.es = ((unsigned long)(&pblock) >> 16);    /* set up param block ptr */
  855.     regs.x.bx = (unsigned int)(&pblock);
  856. #endif
  857. #if    LATTICE
  858.     if ((intdosx(®s, ®s, &segreg) & CFLAG) == 0) {
  859.         regs.h.ah = 0x4d;    /* get child process return code */
  860.         intdos(®s, ®s);    /* go do it */
  861.         rval = regs.x.ax;    /* save child's return code */
  862.     } else
  863.         rval = -_oserr;        /* failed child call */
  864. #endif
  865. #if    AZTEC
  866.     if ((sysint(0x21, ®s, ®s) & CFLAG) == 0) {
  867.         regs.h.ah = 0x4d;    /* get child process return code */
  868.         sysint(0x21, ®s, ®s);    /* go do it */
  869.         rval = regs.x.ax;    /* save child's return code */
  870.     } else
  871.         rval = -errno;        /* failed child call */
  872. #endif
  873. #if    MWC
  874.     intcall(®s, ®s, DOSINT);
  875.     if ((regs.x.flags & CFLAG) == 0) {
  876.         regs.h.ah = 0x4d;    /* get child process return code */
  877.         intcall(®s, ®s, DOSINT);    /* go do it */
  878.         rval = regs.x.ax;    /* save child's return code */
  879.     } else
  880.         rval = -errno;        /* failed child call */
  881. #endif
  882. #if    TURBO | IC | MSC | DTL | ZTC
  883.     intdosx(®s, ®s, &segreg);
  884.     if (regs.x.cflag == 0) {
  885.         regs.h.ah = 0x4d;    /* get child process return code */
  886.         intdos(®s, ®s);    /* go do it */
  887.         rval = regs.x.ax;    /* save child's return code */
  888.     } else
  889. #if    IC
  890.         rval = -1;
  891. #else /* IC */
  892.         rval = -_doserrno;    /* failed child call */
  893. #endif /* IC */
  894. #endif
  895.     return((rval < 0) ? FALSE : TRUE);
  896. }
  897.  
  898. /* return a system dependant string with the current time */
  899.  
  900. char *PASCAL NEAR timeset()
  901.  
  902. {
  903. #if    MWC | TURBO | IC | MSC | ZTC
  904.     register char *sp;    /* temp string pointer */
  905.     char buf[16];        /* time data buffer */
  906.     extern char *ctime();
  907.  
  908. #if    IC
  909.     time((time_t *)buf);
  910.     sp = ctime((time_t *)buf);
  911. #else
  912.     time(buf);
  913.     sp = ctime(buf);
  914. #endif
  915.     sp[strlen(sp)-1] = 0;
  916.     return(sp);
  917. #else
  918.     return(errorm);
  919. #endif
  920. }
  921.  
  922. #if    TURBO
  923. /*    FILE Directory routines        */
  924.  
  925. char path[NFILEN];    /* path of file to find */
  926. char rbuf[NFILEN];    /* return file buffer */
  927.  
  928. /*    do a wild card directory search (for file name completion) */
  929.  
  930. char *PASCAL NEAR getffile(fspec)
  931.  
  932. char *fspec;    /* pattern to match */
  933.  
  934. {
  935.     register int index;        /* index into various strings */
  936.     register int point;        /* index into other strings */
  937.     register int extflag;        /* does the file have an extention? */
  938.     char fname[NFILEN];        /* file/path for DOS call */
  939.  
  940.     /* first parse the file path off the file spec */
  941.     strcpy(path, fspec);
  942.     index = strlen(path) - 1;
  943.     while (index >= 0 && (path[index] != '/' &&
  944.                 path[index] != '\\' && path[index] != ':'))
  945.         --index;
  946.     path[index+1] = 0;
  947.  
  948.     /* check for an extension */
  949.     point = strlen(fspec) - 1;
  950.     extflag = FALSE;
  951.     while (point > index) {
  952.         if (fspec[point] == '.') {
  953.             extflag = TRUE;
  954.             break;
  955.         }
  956.         point--;
  957.     }
  958.  
  959.     /* construct the composite wild card spec */
  960.     strcpy(fname, path);
  961.     strcat(fname, &fspec[index+1]);
  962.     strcat(fname, "*");
  963.     if (extflag == FALSE)
  964.         strcat(fname, ".*");
  965.  
  966.     /* and call for the first file */
  967.     if (findfirst(fname, &fileblock, FA_DIREC) == -1)
  968.         return(NULL);
  969.  
  970.     /* return the first file name! */
  971.     strcpy(rbuf, path);
  972.     strcat(rbuf, fileblock.ff_name);
  973.     mklower(rbuf);
  974.     if (fileblock.ff_attrib == 16)
  975.         strcat(rbuf, DIRSEPSTR);
  976.     return(rbuf);
  977. }
  978.  
  979. char *PASCAL NEAR getnfile()
  980.  
  981. {
  982.     register int index;        /* index into various strings */
  983.     register int point;        /* index into other strings */
  984.     register int extflag;        /* does the file have an extention? */
  985.     char fname[NFILEN];        /* file/path for DOS call */
  986.  
  987.     /* and call for the first file */
  988.     if (findnext(&fileblock) == -1)
  989.         return(NULL);
  990.  
  991.     /* return the first file name! */
  992.     strcpy(rbuf, path);
  993.     strcat(rbuf, fileblock.ff_name);
  994.     mklower(rbuf);
  995.     if (fileblock.ff_attrib == 16)
  996.         strcat(rbuf, DIRSEPSTR);
  997.     return(rbuf);
  998. }
  999. #else
  1000. #if    MSC | ZTC
  1001. /*    FILE Directory routines        */
  1002.  
  1003. char path[NFILEN];    /* path of file to find */
  1004. char rbuf[NFILEN];    /* return file buffer */
  1005.  
  1006. /*    do a wild card directory search (for file name completion) */
  1007.  
  1008. char *PASCAL NEAR getffile(fspec)
  1009.  
  1010. char *fspec;    /* pattern to match */
  1011.  
  1012. {
  1013.     register int index;        /* index into various strings */
  1014.     register int point;        /* index into other strings */
  1015.     register int extflag;        /* does the file have an extention? */
  1016.     char fname[NFILEN];        /* file/path for DOS call */
  1017.  
  1018.     /* first parse the file path off the file spec */
  1019.     strcpy(path, fspec);
  1020.     index = strlen(path) - 1;
  1021.     while (index >= 0 && (path[index] != '/' &&
  1022.                 path[index] != '\\' && path[index] != ':'))
  1023.         --index;
  1024.     path[index+1] = 0;
  1025.  
  1026.     /* check for an extension */
  1027.     point = strlen(fspec) - 1;
  1028.     extflag = FALSE;
  1029.     while (point > index) {
  1030.         if (fspec[point] == '.') {
  1031.             extflag = TRUE;
  1032.             break;
  1033.         }
  1034.         point--;
  1035.     }
  1036.  
  1037.     /* construct the composite wild card spec */
  1038.     strcpy(fname, path);
  1039.     strcat(fname, &fspec[index+1]);
  1040.     strcat(fname, "*");
  1041.     if (extflag == FALSE)
  1042.         strcat(fname, ".*");
  1043.  
  1044.     /* and call for the first file */
  1045.     if (_dos_findfirst(fname, _A_NORMAL|_A_SUBDIR, &fileblock) != 0)
  1046.         return(NULL);
  1047.  
  1048.     /* return the first file name! */
  1049.     strcpy(rbuf, path);
  1050.     strcat(rbuf, fileblock.name);
  1051.     mklower(rbuf);
  1052.     if (fileblock.attrib == 16)
  1053.         strcat(rbuf, DIRSEPSTR);
  1054.     return(rbuf);
  1055. }
  1056.  
  1057. char *PASCAL NEAR getnfile()
  1058.  
  1059. {
  1060.     register int index;        /* index into various strings */
  1061.     register int point;        /* index into other strings */
  1062.     register int extflag;        /* does the file have an extention? */
  1063.     char fname[NFILEN];        /* file/path for DOS call */
  1064.  
  1065.     /* and call for the first file */
  1066.     if (_dos_findnext(&fileblock) != 0)
  1067.         return(NULL);
  1068.  
  1069.     /* return the first file name! */
  1070.     strcpy(rbuf, path);
  1071.     strcat(rbuf, fileblock.name);
  1072.     mklower(rbuf);
  1073.     if (fileblock.attrib == 16)
  1074.         strcat(rbuf, DIRSEPSTR);
  1075.     return(rbuf);
  1076. }
  1077. #else
  1078. char *PASCAL NEAR getffile(fspec)
  1079.  
  1080. char *fspec;    /* file to match */
  1081.  
  1082. {
  1083.     return(NULL);
  1084. }
  1085.  
  1086. char *PASCAL NEAR getnfile()
  1087.  
  1088. {
  1089.     return(NULL);
  1090. }
  1091. #endif
  1092. #endif
  1093. #endif
  1094.